#ifndef MPEGTS_IO
#define MPEGTS_IO

/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef __cplusplus
    extern "C" {
#endif


#include <stdint.h>
#include <pthread.h>
#include "utils.h"

#define TS_IO_IDX_HEADER						0xD0FF


#define MPEGTS_IO_READ_START					1
#define MPEGTS_IO_READ_TIMECODE					2
#define MPEGTS_IO_READ_LIVE						3

#define MPEGTS_IO_MODE_CREATE					0
#define MPEGTS_IO_MODE_SERVE					1
#define MPEGTS_IO_MODE_REGEN_IDX				2
#define MPEGTS_IO_MODE_REGEN_IDX_FIRST			3

#define MPEGTS_IO_MAX_FILEUNITS					75
#define MPEGTS_IO_FILEUNIT_EXTRA_COUNT			5

#define MPEGTS_IO_INVALID						0xFFFFFFFFFFFFFFFF
#define MPEGTS_IO_LIVE_POS						MPEGTS_IO_INVALID

#define MPEGTS_IO_MAX_SIZE_DEFAULT 				(10434000 * 20)
//#define MPEGTS_IO_MAX_SIZE_DEFAULT 			(10434000 * 2)
//#define MPEGTS_IO_MAX_SIZE_DEFAULT 		(104340000)
//#define MPEGTS_IO_MAX_SIZE_DEFAULT 		(104340000)

/*
	uint8_t 	live_flag
	uint16_t	segment count
	uint16_t	lowest segment number (pts/dts)
	uint16_t	highest segment number (pts/dts)

	MPEGTS_IO_TIMESTAMP_STRUCT .....
*/

struct mpegts_io_packet
{
	uint8_t stream_type;
	uint16_t pid;
	uint8_t start; // payload start indicator
	uint8_t adapt; // adaptation field
	uint8_t *data;
	uint32_t data_len;
	uint64_t pts;
	uint64_t dts;
	uint8_t frame_type;
	MPEGTS_PAT *pat;
	MPEGTS_PMT *pmt;
	MPEGTS_PACKET *packet;
};
typedef struct mpegts_io_packet MPEGTS_IO_PACKET_STRUCT;

struct mpegts_io_idxunit
{
//	uint32_t packet_number;
	uint64_t packet_number;
	uint64_t pts;
	uint64_t dts;
	struct mpegts_io_idxunit * next;
};
typedef struct mpegts_io_idxunit MPEGTS_IO_IDXUNIT_STRUCT;

struct mpegts_io_fileunit
{
	uint64_t					idx_ctime;
	uint64_t					idx_mtime;
	uint64_t					rec_ctime;
	uint64_t					rec_mtime;
	uint64_t					mpg_ctime;
	uint64_t					mpg_mtime;

	uint32_t id;
	char * ts_filename;
	char * idx_filename;
	char * rec_filename;

	FILE *idx_fhandle;
	FILE *ts_fhandle;
	FILE *rec_fhandle;

	uint64_t packet_count;
	uint32_t index_count;

	off_t current_file_size;
	off_t max_file_size;

	uint32_t idx_single_struct_sz;
	struct mpegts_io_struct *parent;

	MPEGTS_IO_IDXUNIT_STRUCT *first_idx;
	MPEGTS_IO_IDXUNIT_STRUCT *current_idx;
	MPEGTS_IO_IDXUNIT_STRUCT *last_idx;
	uint64_t first_pts;

	uint16_t reader_count;

	pthread_mutex_t update_lock;
	pthread_mutexattr_t *update_lock_attr;

	struct mpegts_io_fileunit *next;
	void * memory_handle;

	int64_t last_update;
	int64_t last_idx_pts;

//	time_t last_update;
//	time_t last_idx_pts;
	UTILS_DATAPAIR_STRUCT *extra_data[MPEGTS_IO_FILEUNIT_EXTRA_COUNT];
//	void * extra_data[MPEGTS_IO_FILEUNIT_EXTRA_COUNT];
	
//	int (*mpegts_io_write_ts)(struct mpegts_io_fileunit *, struct mpegts_io_packet *);

};
typedef struct mpegts_io_fileunit MPEGTS_IO_FILEUNIT_STRUCT;


/*
 When creating a reader,

*/
struct mpegts_io_reader
{
	MPEGTS_IO_FILEUNIT_STRUCT *fileunit;
//	off_t read_pos;
	FILE *ts_fhandle;
	int ts_handle;
	uint64_t packet_index;
	uint64_t packets_until_end;
	uint8_t *data;
	uint32_t data_len;
	struct mpegts_io_struct *parent;
	struct mpegts_io_reader *next;
//	pthread_mutex_t lock;
};
typedef struct mpegts_io_reader MPEGTS_IO_READER_STRUCT;

struct mpegts_io_struct
{
	UTILS_DATAPAIR_STRUCT		*extra_data[MPEGTS_IO_FILEUNIT_EXTRA_COUNT];
	void 						*extra_data2;
	uint8_t						reused;
	uint8_t						id;
	uint8_t						mode;
	char 						*base_filename;
	char 						*description;
	uint8_t						is_last;
	uint16_t					video_pid;
	uint16_t					pmt_pid;
	uint8_t					 	islive;
	uint8_t					 	isrecording;
	uint32_t 					max_file_size;
	uint32_t 					max_file_life;

	uint16_t					cleanup_wait_time;
	pthread_t 					cleanup_thread;
	pthread_mutex_t 			update_lock;
	pthread_mutexattr_t 		*update_lock_attr;

	uint8_t						use_mem_only;
	uint8_t 					*write_cache;
	uint32_t 					write_cache_size;
	uint32_t 					write_cache_pos;
	//time_t						last_flush_time;
	int64_t						last_flush_time;
	MPEGTS_IO_FILEUNIT_STRUCT	*first_fileunit;
	MPEGTS_IO_FILEUNIT_STRUCT	*current_fileunit;
	int (*mpegts_io_write_ts)(struct mpegts_io_fileunit *, struct mpegts_io_packet *);

	uint8_t (*cb_seek_to_time)(MPEGTS_IO_READER_STRUCT *, uint64_t);
	uint64_t (*cb_get_current_time)(MPEGTS_IO_READER_STRUCT *);
	uint64_t (*cb_get_start_time)(MPEGTS_IO_READER_STRUCT *);
	uint64_t (*cb_get_end_time)(MPEGTS_IO_READER_STRUCT *);

	struct mpegts_io_struct		*next;
	struct mpegts_io_struct		*next2;

};
typedef struct mpegts_io_struct MPEGTS_IO_STRUCT;

struct mpegts_io_recordings_struct
{
	uint64_t			sequence_num;
	uint32_t			count;
	MPEGTS_IO_STRUCT	*first_io_struct;
	MPEGTS_IO_STRUCT	*current_io_struct;
};
typedef struct mpegts_io_recordings_struct MPEGTS_IO_RECORDINGS_STRUCT;


struct mpegts_io_init_args_struct
{
	char *filename_base;
	uint32_t max_segment_size;
	uint32_t max_segment_life;
	uint8_t mode;
	uint8_t stream_only;
	uint8_t recording;
	uint32_t cleanup_wait_time;
	uint32_t write_cache_size;

	void *extra_data2;
	uint8_t (*cb_seek_to_time)(MPEGTS_IO_READER_STRUCT *, uint64_t);
	uint64_t (*cb_get_current_time)(MPEGTS_IO_READER_STRUCT *);
	uint64_t (*cb_get_start_time)(MPEGTS_IO_READER_STRUCT *);
	uint64_t (*cb_get_end_time)(MPEGTS_IO_READER_STRUCT *);
};
typedef struct mpegts_io_init_args_struct MPEGTS_IO_INIT_ARGS_STRUCT;
#ifdef USE_GLIB

#include <glib.h>


struct mpegts_io_regen_struct
{
//	pthread_t tid;
//	uint8_t done;
	uint8_t inited;
	char *filename;
	off_t start;
	off_t end;
	int index;
	GSList *idx_glist;
};
typedef struct mpegts_io_regen_struct MPEGTS_IO_REGEN_STRUCT;



int mpegts_io_add_data(MPEGTS_IO_STRUCT *, MPEGTS_IO_PACKET_STRUCT *);
int8_t mpegts_io_close(MPEGTS_IO_STRUCT *, uint8_t);
//MPEGTS_IO_STRUCT * mpegts_io_init(char *, uint32_t, uint32_t, uint8_t);
MPEGTS_IO_STRUCT * mpegts_io_init(MPEGTS_IO_INIT_ARGS_STRUCT *);
MPEGTS_IO_PACKET_STRUCT *mpegts_io_parse_packet(uint8_t *, uint32_t, MPEGTS_IO_PACKET_STRUCT *);
MPEGTS_IO_READER_STRUCT * mpegts_io_get_reader(MPEGTS_IO_STRUCT *, uint8_t, uint64_t);
int mpegts_io_disconnect_reader(MPEGTS_IO_READER_STRUCT *);
uint8_t _mpegts_io_read_idx_mpg(MPEGTS_IO_FILEUNIT_STRUCT *);
void _mpegts_io_print_idxs(MPEGTS_IO_FILEUNIT_STRUCT *);
uint32_t mpegts_io_get_packet_remaining(MPEGTS_IO_READER_STRUCT *);
uint32_t mpegts_io_get_packet_count(MPEGTS_IO_READER_STRUCT *, uint32_t);


uint64_t mpegts_io_get_reader_pos(MPEGTS_IO_READER_STRUCT *);
uint64_t mpegts_io_get_reader_endpos(MPEGTS_IO_READER_STRUCT *);
uint64_t mpegts_io_get_reader_startpos(MPEGTS_IO_READER_STRUCT *);
uint64_t mpegts_io_get_reader_startpos2(MPEGTS_IO_READER_STRUCT *);
uint8_t mpegts_io_set_reader_pos(MPEGTS_IO_READER_STRUCT *, uint64_t);

uint64_t mpegts_io_get_reader_sz_pos(MPEGTS_IO_READER_STRUCT *);
uint64_t mpegts_io_get_reader_sz_endpos(MPEGTS_IO_READER_STRUCT *);
uint64_t mpegts_io_get_reader_sz_startpos(MPEGTS_IO_READER_STRUCT *);
uint8_t mpegts_io_set_reader_sz_pos(MPEGTS_IO_READER_STRUCT *, uint64_t);

int mpegts_io_regen_idx(char *, int, int);

UTILS_DATAPAIR_STRUCT * mpegts_io_get_rec_data(MPEGTS_IO_STRUCT *);
MPEGTS_IO_RECORDINGS_STRUCT * mpegts_io_load_recordings(char *, MPEGTS_IO_RECORDINGS_STRUCT *);
void mpegts_io_cleanup_recordings(char *);

#endif

#ifdef __cplusplus
    }
#endif



#endif

